package com.jwdemo 
{
	import com.adobe.utils.*;
	
	import flash.display.*;
	import flash.display3D.*;
	import flash.display3D.textures.*;
	import flash.events.*;
	import flash.geom.Matrix;
	import flash.geom.Matrix3D;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	import flash.utils.Dictionary;
//	import flash.display.BitmapData;

	//import com.jwdemo.QuadBatch ; 
	
	public class RenderHelperStage3D
	{
		private var context3D:Context3D;		
		private var shaderProgram:Program3D;	
		private var vertexBuffer:VertexBuffer3D;	
		private var indexBuffer:IndexBuffer3D;		// the uploaded indices of each vertex of the mesh
		private var sheetDictionary:Dictionary	=	new Dictionary() ;
		private var imageDictionary:Dictionary	=	new Dictionary() ;		// maps image names to sheets

		private var screenDim:Object ;
		private var screenWidth:Number ;
		private var screenHeight:Number ;
		private	var mtx:Matrix 				= 	new Matrix();
		private var _oMatrix:Matrix3D 		=	new Matrix3D() ;
		private var batchRender:uint 				= 	0 ;

		//	private var uvData:Vector.<Number> ;
		
		public function RenderHelperStage3D(ctx:Context3D, scrnDim:Object )
		{
				context3D	=	ctx ;
				screenDim	=	scrnDim ;	
				screenWidth	=	scrnDim.width ;
				screenHeight=	scrnDim.height ;

				_oMatrix.copyRowFrom(0,new Vector3D(2/screenWidth,0,0,-1)) ;
				_oMatrix.copyRowFrom(1,new Vector3D(0,-2/screenHeight,0,1)) ;


				init3DShaders() ;

				context3D.configureBackBuffer(screenDim.width, screenDim.height, 0, false);
				context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);            

				
		}
		
		
		private function getCachedBatchFromSheet(sheet:SpriteSheet) : QuadBatch
		{
			var qb:QuadBatch		=	sheetDictionary[sheet] ;
			if (qb == null) 
			{
				qb = new QuadBatch(context3D,sheet,_oMatrix) ;
				sheetDictionary[sheet] = qb ;
			}
			return qb ;
		}

		private function getCachedSheetFromImageName(name:String) : SpriteSheet
		{

			var ss:SpriteSheet		=	imageDictionary[name] ;
			if (ss == null)
			{
				var bmd:BitmapData = GameBitMaps.GetBitMap(name)  // todo - tidy this up!
				ss = new SpriteSheet(bmd,bmd.width,bmd.height) ;
				imageDictionary[name] = ss ;
			}
			return ss ;
		}

		public function start() : void
		{
			context3D.clear(0,0,0,1); 
		}

		public function end() : void
		{
			
			// todo - each batch to have its own shader program
			
			batchRender	=	0 ;
	
		//	context3D.setProgram ( shaderProgram ) ;

			//var qBatch:QuadBatch = getCachedBatchFromSheet(sheet) ;
			for each (var qBatch:QuadBatch in sheetDictionary)
			{
				qBatch.draw() ;		
				batchRender++ ;
			}
			
			context3D.present();

		}
		
		
		
		public function drawSheet(sheet:SpriteSheet, x:Number, y:Number, 
								  frame:int = 0, 
								  rot:Number = 0.0, sx:Number = 1, sy:Number = 1, zd:Number = 0) : void
		{
			
			var qBatch:QuadBatch = getCachedBatchFromSheet(sheet) ;
			qBatch.drawSheet(x, y, frame, rot, sx, sy, zd) ;
		}


		// Image
		public function drawImage(imageName:String, x:Number, y:Number, 
								  rot:Number = 0.0, sx:Number = 1, sy:Number = 1) : void
		{
			// Create a Sheet for an image - 
			var qBatch:QuadBatch = getCachedBatchFromSheet(getCachedSheetFromImageName(imageName)) ;
			qBatch.drawSheet(x, y, 0, rot, sx, sy) ;
		}

		private function countDict(dict:Dictionary):uint 
		{
			var count:uint = 0 ;
			
			for each (var v:Object in dict)
			{
				count++ ;					
			}
			return count ;
		}
		
		
		private function getDrawStats():uint 
		{
			var count:uint  = 0 ;
			for each (var qb:QuadBatch in sheetDictionary)
			{
				count += qb.numberTriangles() ;					
			}
			return count ;
		}
		
		public function toString():String 
		{
			return "RHelper3D batchRender "+ batchRender+ " triangles "+getDrawStats() ;
		}
		
		
		private function drawBuffersXXX(	tilesetTexture:Texture,
										vertexdata:Vector.<Number>,
									 	meshindexdata:Vector.<uint>) : void
		{


			// x,y,z,u,v,rot,sx,sy
			var numEntries:uint		=	vertexdata.length / 5;
			
			vertexBuffer = context3D.createVertexBuffer(numEntries, 5); 
			vertexBuffer.uploadFromVector(vertexdata, 0, numEntries);
			
			indexBuffer = context3D.createIndexBuffer(meshindexdata.length);
			indexBuffer.uploadFromVector(meshindexdata, 0, meshindexdata.length);

			
			var _pMatrix:Matrix3D = new Matrix3D() ;
			// Do this in AGAL?
			_pMatrix.identity() ;

			// set up vc0 (and vc1,vc2,vc3) for out matrix.
			context3D.setProgramConstantsFromMatrix(
				Context3DProgramType.VERTEX, 
				0, _pMatrix, true );		//vc0

			// associate the vertex data   with current shader program va0 reg
			context3D.setVertexBufferAt(0 /* va0 */, vertexBuffer, 0 /* 1st offset (base 0) */, 
				Context3DVertexBufferFormat.FLOAT_3); 
			// Set up va1 to contain UV data
			context3D.setVertexBufferAt(1 /* va1 */, vertexBuffer, 3,  /* 3rd offset base 0 */
				Context3DVertexBufferFormat.FLOAT_2); 
			
			// fs0 contains tileset Texture.
			context3D.setTextureAt(0 /* fs0 */, tilesetTexture) ;  

			// Clear context 
			context3D.clear(0,0,1,1); 
			context3D.drawTriangles(indexBuffer, 0,meshindexdata.length/3) ;
			context3D.present();

		}

		
		
		private function init3DShaders() : void
		{
			
			// The 3d back buffer size is in pixels
			//context3D.configureBackBuffer(screenDim.width, screenDim.height, 0, true);
		
			// A simple vertex shader which does a 3D transformation
			var vertexShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler() ;
			
			vertexShaderAssembler.assemble
				( 
					Context3DProgramType.VERTEX,
					// 4x4 matrix multiply to get camera angle	
					//"m44 op, va0, vc4\n" +
					"m44 op, va0, vc0\n" +
					// tell fragment shader about UV
					"mov v1, va1\n"
				);			
			
			
			var fragmentShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
			
			fragmentShaderAssembler.assemble
				( 
					Context3DProgramType.FRAGMENT,	
					// grab the texture color from texture fs0
					// using the UV coordinates stored in v1
					//				"tex ft0, v1, fs0 <2d,repeat,miplinear>\n" +	
					"tex ft0, v1, fs0 <2d,linear, nomip>\n" +	
					"mov oc,ft0\n"
				);

					
			shaderProgram = context3D.createProgram();
			shaderProgram.upload(vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);

		}
	

	}
}